package peer.model.transfer.file;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import peer.model.consts.TransferConsts;
import peer.model.transfer.Codec;
import peer.util.TransferUtil;

/**
 * Utility class which receives files.
 * @author Guido
 */

public class FileReceiver {

	public static void receiveFile(Socket socket, String path, String downloadID){
		FileOutputStream fileOut=null;
		try {
			InputStream input = socket.getInputStream();

			/*Receive the metadata*/
			ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
			receive(input, byteArray, 256*TransferConsts.KILO_BYTE, (int) receiveSize(input));
			String fileName = new String(byteArray.toByteArray());

			fileName=(System.currentTimeMillis() * Math.random()) + fileName;

			/*Receive the file*/
			long fileSize = receiveSize(input);
			Integer partitions = TransferUtil.partition(fileSize);
			fileOut = new FileOutputStream(path + "/" + fileName);

			for(Integer i = 0; i < partitions; i++){
				receive(input, fileOut, TransferConsts.MEGA_BYTE, TransferConsts.TRANSFER_BUFFER_SIZE);
				//System.out.println("[PEER/DOWNLOAD " + downloadID + "] Partition " + (i+1) + " of " + (partitions+1) + "  - size: " + TransferConsts.PARTITION_SIZE + " Bytes OK");
			}

			receive(input, fileOut, TransferConsts.MEGA_BYTE, (int) (fileSize - partitions * TransferConsts.TRANSFER_BUFFER_SIZE));
			//System.out.println("[PEER/DOWNLOAD " + downloadID + "] Partition " + (partitions+1) + " of " + (partitions+1) + "  - size: " + ((int) (fileSize - partitions * TransferConsts.PARTITION_SIZE)) + " Bytes OK");
		} catch (IOException e) {
			e.printStackTrace(System.err);
		}finally{
			try {
				fileOut.flush();
				fileOut.close();
			} catch (IOException e) {
				e.printStackTrace(System.err);
			}
		}
	}

	public static long receiveSize(InputStream input){
		ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
		receive(input, byteArray, Codec.SIZE_BYTES, Codec.SIZE_BYTES);
		return Codec.decode(byteArray.toByteArray());
	}

	public static void receive(InputStream input, OutputStream output, Integer bufferSize, Integer dataSize){
		byte[] buffer = new byte[bufferSize];
		Integer received = 0;
		Integer readed = 0;

		try {
			while((readed = input.read(buffer, 0, (Integer) Math.min(dataSize - received, bufferSize))) > 0){
				output.write(buffer, 0, readed);
				received += readed;
			}
		} catch (IOException e) {
			e.printStackTrace(System.err);
		}
	}
}
